package com.googlecode.stil.playground;

import android.hardware.SensorManager;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.MassData;
import org.andengine.audio.sound.Sound;
import org.andengine.audio.sound.SoundFactory;
import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.scene.IOnAreaTouchListener;
import org.andengine.entity.scene.IOnSceneTouchListener;
import org.andengine.entity.scene.ITouchArea;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.entity.shape.Shape;
import org.andengine.entity.sprite.Sprite;
import org.andengine.extension.physics.box2d.PhysicsConnector;
import org.andengine.extension.physics.box2d.PhysicsFactory;
import org.andengine.extension.physics.box2d.PhysicsWorld;
import org.andengine.extension.physics.box2d.util.Vector2Pool;
import org.andengine.input.sensor.acceleration.AccelerationData;
import org.andengine.input.sensor.acceleration.IAccelerationListener;
import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.util.debug.Debug;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class KickBallActivity extends StilBaseGameActivity implements IAccelerationListener, IOnSceneTouchListener, IOnAreaTouchListener {

	private static final int CAMERA_WIDTH = 480;
	private static final int CAMERA_HEIGHT = 720;

	private ITextureRegion ballTextureRegion;
	private Sound ballSound;

	private static float BALL_WIDTH = 0;
	private static float BALL_HEIGHT = 0;

	private FixtureDef ballDef = PhysicsFactory.createFixtureDef(0.4f, 0.4f, 0.4f);
	private FixtureDef wallDef = PhysicsFactory.createFixtureDef(1.0f, 0.0f, 0.8f);

	private PhysicsWorld physics;
	private float gravityX, gravityY;

	private Camera camera;

	private List<Shape> balls = new ArrayList<Shape>();

	@Override
	public EngineOptions onCreateEngineOptions() {
		camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
		EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.PORTRAIT_FIXED, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), camera);
		engineOptions.getAudioOptions().setNeedsSound(true);
		return engineOptions;
	}

	@Override
	public void onCreateResources() {
		BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
		BitmapTextureAtlas textureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 122, 122, TextureOptions.BILINEAR);
		this.ballTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(textureAtlas, this, "soccer_ball.png", 0, 0);
		textureAtlas.load();

		BALL_WIDTH = this.ballTextureRegion.getWidth();
		BALL_HEIGHT = this.ballTextureRegion.getHeight();

		SoundFactory.setAssetBasePath("sfx/");
		try {
			this.ballSound = SoundFactory.createSoundFromAsset(getEngine().getSoundManager(), this, "FootballKick.mp3");
		} catch (final IOException e) {
			Debug.e(e);
		}
	}

	@Override
	public Scene onCreateScene() {

		final Scene scene = new Scene();
		scene.setBackground(new Background(0.5f, 0.3f, 0.5f));
		scene.setOnAreaTouchListener(this);
		scene.setOnSceneTouchListener(this);

		initPhisics(scene);
		buildWalls(scene);

		return scene;
	}

	@Override
	public void onPopulateScene(Scene pScene, OnPopulateSceneCallback pOnPopulateSceneCallback) {
		pOnPopulateSceneCallback.onPopulateSceneFinished();
	}

	@Override
	public void onResumeGame() {
		super.onResumeGame();

		this.enableAccelerationSensor(this);
	}

	@Override
	public void onPauseGame() {
		super.onPauseGame();

		this.disableAccelerationSensor();
	}

	private void buildWalls(Scene scene) {
		Rectangle roof = new Rectangle(0, 0, CAMERA_WIDTH, 5, getVertexBufferObjectManager());
		roof.setColor(1, 0, 0);
		PhysicsFactory.createBoxBody(physics, roof, BodyType.StaticBody, wallDef);
		scene.attachChild(roof);

		Rectangle floor = new Rectangle(0, CAMERA_HEIGHT - 5, CAMERA_WIDTH, 5, getVertexBufferObjectManager());
		floor.setColor(1, 1, 0);
		PhysicsFactory.createBoxBody(physics, floor, BodyType.StaticBody, wallDef);
		scene.attachChild(floor);

		Rectangle left = new Rectangle(0, 0, 5, CAMERA_HEIGHT, getVertexBufferObjectManager());
		left.setColor(0, 0, 1);
		PhysicsFactory.createBoxBody(physics, left, BodyType.StaticBody, wallDef);
		scene.attachChild(left);

		Rectangle right = new Rectangle(CAMERA_WIDTH - 5, 0, 5, CAMERA_HEIGHT, getVertexBufferObjectManager());
		right.setColor(0, 1, 1);
		PhysicsFactory.createBoxBody(physics, right, BodyType.StaticBody, wallDef);
		scene.attachChild(right);
	}

	private void initPhisics(Scene scene) {
		physics = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);
		scene.registerUpdateHandler(physics);
	}

	private void addBall(Scene scene, float x, float y) {
		Shape ball = new Sprite(x, y, ballTextureRegion, getVertexBufferObjectManager());

		Body ballBody = PhysicsFactory.createCircleBody(physics, ball, BodyType.DynamicBody, ballDef);
		MassData mass = ballBody.getMassData();
		mass.I = 0.05f;
		mass.mass = 0.45f;
		ballBody.setMassData(mass);
		ball.setUserData(ballBody);

		scene.registerTouchArea(ball);
		scene.attachChild(ball);

		physics.registerPhysicsConnector(new PhysicsConnector(ball, ballBody, true, true));

		balls.add(ball);
	}

	@Override
	public void onAccelerationAccuracyChanged(final AccelerationData pAccelerationData) {
	}

	@Override
	public void onAccelerationChanged(AccelerationData pAccelerationData) {
		gravityX = pAccelerationData.getX();
		gravityY = pAccelerationData.getY();

		final Vector2 gravity = Vector2Pool.obtain(gravityX, gravityY);
		physics.setGravity(gravity);
		Vector2Pool.recycle(gravity);
	}

	@Override
	public boolean onAreaTouched(TouchEvent pSceneTouchEvent, ITouchArea pTouchArea, float pTouchAreaLocalX, float pTouchAreaLocalY) {
		if (pSceneTouchEvent.isActionDown()) {

			Shape ballShape = balls.get(balls.indexOf(pTouchArea));
			Body ballBody = (Body) ballShape.getUserData();

			System.out.println("(pTouchAreaLocalX, pTouchAreaLocalY): (" + pTouchAreaLocalX + "," + pTouchAreaLocalY + ")");
			System.out.println("(touchEvent.getX(), touchEvent.getY()): (" + pSceneTouchEvent.getX() + "," + pSceneTouchEvent.getY() + ")");

			Vector2 impulse = Vector2Pool.obtain(gravityX * -1f, gravityY * -1f);
			Vector2 point = Vector2Pool.obtain(pTouchAreaLocalX, pTouchAreaLocalY);

			System.out.println("AV Before " + ballBody.getAngularVelocity());
			System.out.println(ballBody.getLocalCenter().x + "," + ballBody.getLocalCenter().y);

			ballSound.play();
			ballBody.applyLinearImpulse(impulse, point);

			System.out.println("AV After " + ballBody.getAngularVelocity());

			Vector2Pool.recycle(impulse);
			Vector2Pool.recycle(point);

			return true;

		}
		return false;
	}

	@Override
	public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
		if (pSceneTouchEvent.isActionDown()) {
			addBall(pScene, pSceneTouchEvent.getX() - BALL_WIDTH / 2, pSceneTouchEvent.getY() - BALL_HEIGHT / 2);
			return true;
		}
		return false;
	}
}